"""
停车场数据可视化模块，用于生成各种图表和报告
"""

import os
import logging
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import matplotlib
from data_analysis import get_parking_stats, get_hourly_traffic, analyze_peak_hours, analyze_parking_duration, analyze_device_errors
from config import REPORT_OUTPUT_PATH

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('visualization')

# 设置中文字体支持
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
matplotlib.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 确保报表输出目录存在
os.makedirs(REPORT_OUTPUT_PATH, exist_ok=True)

def generate_daily_report(date=None, output_dir=None):
    """
    生成每日停车场报表
    
    Args:
        date (str): 日期 (YYYY-MM-DD)，默认为当天
        output_dir (str): 输出目录，默认为配置中的报表目录
    
    Returns:
        str: 生成的报表文件路径
    """
    if date is None:
        date = datetime.now().strftime('%Y-%m-%d')
    
    if output_dir is None:
        output_dir = REPORT_OUTPUT_PATH
    
    logger.info(f"正在生成 {date} 的每日停车场报表")
    
    # 获取当日统计数据
    stats = get_parking_stats(start_date=date, end_date=date)
    
    # 获取每小时车流量
    hourly_data = {}
    for idx, row in stats.iterrows():
        lot_name = row['ParkingLotName']
        hourly_data[lot_name] = get_hourly_traffic(date=date, parking_lot_id=idx+1)
    
    # 创建可视化
    plt.figure(figsize=(15, 12))
    
    # 1. 停车场总体情况
    plt.subplot(2, 2, 1)
    bar_width = 0.35
    index = np.arange(len(stats))
    
    plt.bar(index, stats['TotalEntries'], bar_width, label='总入场车辆')
    plt.bar(index + bar_width, stats['TotalExits'], bar_width, label='总出场车辆')
    
    plt.xlabel('停车场')
    plt.ylabel('车辆数量')
    plt.title('各停车场车辆进出情况')
    plt.xticks(index + bar_width / 2, stats['ParkingLotName'], rotation=45, ha='right')
    plt.legend()
    plt.tight_layout()
    
    # 2. 平均停车时长
    plt.subplot(2, 2, 2)
    plt.bar(stats['ParkingLotName'], stats['AvgParkingDurationMinutes'], color='green')
    plt.xlabel('停车场')
    plt.ylabel('平均停车时长(分钟)')
    plt.title('各停车场平均停车时长')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    
    # 3. 收入情况
    plt.subplot(2, 2, 3)
    plt.bar(stats['ParkingLotName'], stats['TotalRevenue'], color='orange')
    plt.xlabel('停车场')
    plt.ylabel('收入(元)')
    plt.title('各停车场收入情况')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    
    # 4. 当前停车情况
    plt.subplot(2, 2, 4)
    sizes = stats['CurrentlyParked']
    labels = stats['ParkingLotName']
    
    plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
    plt.title('各停车场当前停车占比')
    plt.axis('equal')
    
    # 保存图表
    report_file = os.path.join(output_dir, f'daily_report_{date}.png')
    plt.savefig(report_file, dpi=300, bbox_inches='tight')
    plt.close()
    
    # 为每个停车场生成小时流量图
    for lot_name, hourly in hourly_data.items():
        if len(hourly) > 0:
            plt.figure(figsize=(12, 6))
            plt.bar(hourly['HourOfDay'], hourly['EntryCount'], color='skyblue')
            plt.plot(hourly['HourOfDay'], hourly['EntryCount'], 'r-', marker='o')
            plt.xlabel('小时(24小时制)')
            plt.ylabel('入场车辆数')
            plt.title(f'{lot_name} - {date} 每小时入场车辆')
            plt.xticks(range(0, 24))
            plt.grid(True, linestyle='--', alpha=0.7)
            
            hourly_file = os.path.join(output_dir, f'hourly_traffic_{lot_name}_{date}.png')
            plt.savefig(hourly_file, dpi=300, bbox_inches='tight')
            plt.close()
    
    logger.info(f"每日报表生成完成: {report_file}")
    return report_file

def generate_weekly_report(end_date=None, output_dir=None):
    """
    生成周报表
    
    Args:
        end_date (str): 结束日期 (YYYY-MM-DD)，默认为当天
        output_dir (str): 输出目录，默认为配置中的报表目录
    
    Returns:
        str: 生成的报表文件路径
    """
    if end_date is None:
        end_date = datetime.now().strftime('%Y-%m-%d')
    
    if output_dir is None:
        output_dir = REPORT_OUTPUT_PATH
    
    # 计算起始日期（7天前）
    end_date_obj = datetime.strptime(end_date, '%Y-%m-%d')
    start_date_obj = end_date_obj - timedelta(days=6)
    start_date = start_date_obj.strftime('%Y-%m-%d')
    
    logger.info(f"正在生成周报表: {start_date} 至 {end_date}")
    
    # 获取周统计数据
    stats = get_parking_stats(start_date=start_date, end_date=end_date)
    
    # 分析高峰时段
    peak_hours = analyze_peak_hours(days=7)
    
    # 停车时长分析
    duration_analysis = analyze_parking_duration(days=7)
    
    # 创建可视化
    plt.figure(figsize=(15, 10))
    
    # 1. 周总体情况
    plt.subplot(2, 2, 1)
    bar_width = 0.35
    index = np.arange(len(stats))
    
    plt.bar(index, stats['TotalEntries'], bar_width, label='总入场车辆')
    plt.bar(index + bar_width, stats['TotalExits'], bar_width, label='总出场车辆')
    
    plt.xlabel('停车场')
    plt.ylabel('车辆数量')
    plt.title(f'周报表 ({start_date} 至 {end_date}) - 车辆进出总量')
    plt.xticks(index + bar_width / 2, stats['ParkingLotName'], rotation=45, ha='right')
    plt.legend()
    plt.tight_layout()
    
    # 2. 周收入情况
    plt.subplot(2, 2, 2)
    plt.bar(stats['ParkingLotName'], stats['TotalRevenue'], color='orange')
    plt.xlabel('停车场')
    plt.ylabel('收入(元)')
    plt.title('周收入情况')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    
    # 保存主图表
    report_file = os.path.join(output_dir, f'weekly_report_{start_date}_to_{end_date}.png')
    plt.savefig(report_file, dpi=300, bbox_inches='tight')
    plt.close()
    
    # 生成高峰时段热力图
    if len(peak_hours) > 0:
        for lot_id in peak_hours['ParkingLotID'].unique():
            lot_data = peak_hours[peak_hours['ParkingLotID'] == lot_id]
            lot_name = lot_data['ParkingLotName'].iloc[0]
            
            # 创建星期-小时热力图数据
            heatmap_data = np.zeros((7, 24))
            for _, row in lot_data.iterrows():
                day_idx = row['DayOfWeek'] - 1  # 0-6
                hour_idx = row['HourOfDay']
                heatmap_data[day_idx, hour_idx] = row['EntryCount']
            
            plt.figure(figsize=(14, 7))
            ax = sns.heatmap(heatmap_data, cmap='YlOrRd', 
                            xticklabels=range(24),
                            yticklabels=['周一', '周二', '周三', '周四', '周五', '周六', '周日'])
            plt.xlabel('小时(24小时制)')
            plt.ylabel('星期')
            plt.title(f'{lot_name} - 一周内车流量热力图')
            
            peak_file = os.path.join(output_dir, f'peak_hours_{lot_name}_{start_date}_to_{end_date}.png')
            plt.savefig(peak_file, dpi=300, bbox_inches='tight')
            plt.close()
    
    # 生成停车时长分析图
    if len(duration_analysis) > 0:
        for lot_id in duration_analysis['ParkingLotID'].unique():
            lot_data = duration_analysis[duration_analysis['ParkingLotID'] == lot_id]
            lot_name = lot_data['ParkingLotName'].iloc[0]
            
            plt.figure(figsize=(12, 6))
            
            # 按照时长类别的顺序进行排序
            duration_order = ['1小时以内', '1-2小时', '2-3小时', '3-4小时', '4-6小时', '6-12小时', '12小时以上']
            lot_data['DurationCategory'] = pd.Categorical(lot_data['DurationCategory'], categories=duration_order, ordered=True)
            lot_data = lot_data.sort_values('DurationCategory')
            
            plt.bar(lot_data['DurationCategory'], lot_data['VehicleCount'], color='skyblue')
            plt.xlabel('停车时长')
            plt.ylabel('车辆数量')
            plt.title(f'{lot_name} - 停车时长分布')
            plt.xticks(rotation=45, ha='right')
            
            for i, v in enumerate(lot_data['VehicleCount']):
                plt.text(i, v + 5, f"{lot_data['Percentage'].iloc[i]:.1f}%", ha='center')
            
            plt.tight_layout()
            duration_file = os.path.join(output_dir, f'duration_analysis_{lot_name}_{start_date}_to_{end_date}.png')
            plt.savefig(duration_file, dpi=300, bbox_inches='tight')
            plt.close()
    
    logger.info(f"周报表生成完成: {report_file}")
    return report_file

def generate_monthly_report(month=None, year=None, output_dir=None):
    """
    生成月度报表
    
    Args:
        month (int): 月份 (1-12)，默认为当前月
        year (int): 年份，默认为当前年
        output_dir (str): 输出目录，默认为配置中的报表目录
    
    Returns:
        str: 生成的报表文件路径
    """
    today = datetime.now()
    
    if month is None:
        month = today.month
    
    if year is None:
        year = today.year
    
    if output_dir is None:
        output_dir = REPORT_OUTPUT_PATH
    
    # 计算月初和月末
    start_date = f"{year}-{month:02d}-01"
    
    # 计算下个月的第一天，然后减去1天，得到当月最后一天
    if month == 12:
        next_month = 1
        next_year = year + 1
    else:
        next_month = month + 1
        next_year = year
    
    end_date_obj = datetime(next_year, next_month, 1) - timedelta(days=1)
    end_date = end_date_obj.strftime('%Y-%m-%d')
    
    logger.info(f"正在生成月度报表: {year}年{month}月")
    
    # 获取月度统计数据
    stats = get_parking_stats(start_date=start_date, end_date=end_date)
    
    # 分析设备故障情况
    device_errors = analyze_device_errors(days=30)
    
    # 创建可视化
    plt.figure(figsize=(15, 12))
    
    # 1. 月度收入情况
    plt.subplot(2, 2, 1)
    plt.bar(stats['ParkingLotName'], stats['TotalRevenue'], color='green')
    plt.xlabel('停车场')
    plt.ylabel('收入(元)')
    plt.title(f'{year}年{month}月 - 各停车场收入')
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    
    # 2. 月度车辆数量
    plt.subplot(2, 2, 2)
    bar_width = 0.35
    index = np.arange(len(stats))
    
    plt.bar(index, stats['TotalEntries'], bar_width, label='入场车辆')
    plt.bar(index + bar_width, stats['UniqueVehicles'], bar_width, label='独立车辆')
    
    plt.xlabel('停车场')
    plt.ylabel('车辆数量')
    plt.title('月度车辆统计')
    plt.xticks(index + bar_width / 2, stats['ParkingLotName'], rotation=45, ha='right')
    plt.legend()
    plt.tight_layout()
    
    # 保存主图表
    report_file = os.path.join(output_dir, f'monthly_report_{year}_{month:02d}.png')
    plt.savefig(report_file, dpi=300, bbox_inches='tight')
    plt.close()
    
    # 生成设备故障分析图
    if len(device_errors) > 0:
        plt.figure(figsize=(12, 8))
        
        # 只显示有故障的设备
        error_data = device_errors[device_errors['ErrorCount'] > 0]
        
        if len(error_data) > 0:
            # 创建标签
            labels = [f"{row['ParkingLotName']}-{row['GateLocation']}" for _, row in error_data.iterrows()]
            
            # 创建堆叠条形图
            plt.figure(figsize=(12, 6))
            plt.bar(labels, error_data['ErrorCount'] - error_data['UnresolvedErrors'], label='已解决')
            plt.bar(labels, error_data['UnresolvedErrors'], bottom=error_data['ErrorCount'] - error_data['UnresolvedErrors'], label='未解决')
            
            plt.xlabel('设备位置')
            plt.ylabel('故障次数')
            plt.title('月度设备故障分析')
            plt.xticks(rotation=45, ha='right')
            plt.legend()
            plt.tight_layout()
            
            errors_file = os.path.join(output_dir, f'device_errors_{year}_{month:02d}.png')
            plt.savefig(errors_file, dpi=300, bbox_inches='tight')
            plt.close()
            
            # 生成平均解决时间图
            plt.figure(figsize=(12, 6))
            # 只选择有解决记录的设备
            resolved_data = error_data[error_data['AvgResolutionTimeMinutes'].notnull()]
            
            if len(resolved_data) > 0:
                labels = [f"{row['ParkingLotName']}-{row['GateLocation']}" for _, row in resolved_data.iterrows()]
                plt.bar(labels, resolved_data['AvgResolutionTimeMinutes'], color='orange')
                plt.xlabel('设备位置')
                plt.ylabel('平均解决时间(分钟)')
                plt.title('设备故障平均解决时间')
                plt.xticks(rotation=45, ha='right')
                plt.tight_layout()
                
                resolution_file = os.path.join(output_dir, f'resolution_time_{year}_{month:02d}.png')
                plt.savefig(resolution_file, dpi=300, bbox_inches='tight')
                plt.close()
    
    logger.info(f"月度报表生成完成: {report_file}")
    return report_file

def generate_custom_report(title, data_frames, chart_types, start_date=None, end_date=None, output_dir=None):
    """
    生成自定义报表
    
    Args:
        title (str): 报表标题
        data_frames (list): 包含多个Pandas DataFrame的列表
        chart_types (list): 图表类型列表 ('bar', 'line', 'pie', 'heatmap')
        start_date (str): 起始日期，可选
        end_date (str): 结束日期，可选
        output_dir (str): 输出目录，默认为配置中的报表目录
    
    Returns:
        str: 生成的报表文件路径
    """
    if output_dir is None:
        output_dir = REPORT_OUTPUT_PATH
    
    date_str = ''
    if start_date and end_date:
        date_str = f"{start_date}_to_{end_date}"
    elif start_date:
        date_str = start_date
    elif end_date:
        date_str = end_date
    else:
        date_str = datetime.now().strftime('%Y%m%d')
    
    logger.info(f"正在生成自定义报表: {title}")
    
    # 创建图表
    n_charts = len(data_frames)
    if n_charts == 0:
        logger.warning("没有数据用于生成报表")
        return None
    
    # 确定图表布局
    if n_charts <= 2:
        nrows, ncols = 1, n_charts
    elif n_charts <= 4:
        nrows, ncols = 2, 2
    elif n_charts <= 6:
        nrows, ncols = 2, 3
    else:
        nrows, ncols = 3, 3
    
    plt.figure(figsize=(ncols * 6, nrows * 5))
    
    for i, (df, chart_type) in enumerate(zip(data_frames, chart_types)):
        if len(df) == 0:
            continue
        
        plt.subplot(nrows, ncols, i+1)
        
        if chart_type == 'bar':
            # 假设第一列是标签，第二列是值
            x = df.iloc[:, 0].values
            y = df.iloc[:, 1].values
            plt.bar(x, y)
            plt.xticks(rotation=45, ha='right')
        
        elif chart_type == 'line':
            # 假设第一列是X轴，其余列是Y轴的不同系列
            x = df.iloc[:, 0].values
            for col in df.columns[1:]:
                plt.plot(x, df[col].values, marker='o', label=col)
            plt.legend()
            plt.xticks(rotation=45, ha='right')
        
        elif chart_type == 'pie':
            # 假设第一列是标签，第二列是值
            labels = df.iloc[:, 0].values
            sizes = df.iloc[:, 1].values
            plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
            plt.axis('equal')
        
        elif chart_type == 'heatmap':
            # 假设DataFrame是热力图数据
            sns.heatmap(df, cmap='YlOrRd', annot=True, fmt=".1f")
        
        plt.title(df.name if hasattr(df, 'name') else f'图表 {i+1}')
        plt.tight_layout()
    
    # 添加总标题
    plt.suptitle(title, fontsize=16, y=1.02)
    
    # 保存图表
    report_file = os.path.join(output_dir, f'custom_report_{title.replace(" ", "_")}_{date_str}.png')
    plt.savefig(report_file, dpi=300, bbox_inches='tight')
    plt.close()
    
    logger.info(f"自定义报表生成完成: {report_file}")
    return report_file

if __name__ == "__main__":
    # 测试可视化功能
    print("正在测试可视化功能...")
    
    # 生成每日报表
    daily_report = generate_daily_report()
    print(f"每日报表已生成: {daily_report}")
    
    # 生成周报表
    weekly_report = generate_weekly_report()
    print(f"周报表已生成: {weekly_report}")
    
    # 生成月度报表
    monthly_report = generate_monthly_report()
    print(f"月度报表已生成: {monthly_report}") 